﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.ComponentModel;

namespace TFDP.SimpleProcessor
{
    [XmlRoot(ElementName = "TemplateMapping", IsNullable = true, Namespace = "http://tfdp.com/2010/ProjectConfiguration")]
    [Category("Mappings")]
    [Browsable(true)]
    public sealed class TemplateMapping : INotifyPropertyChanged, IEquatable<TemplateMapping>, ICloneable
    {
        #region Backing fields
        private string type;
        private string template;
        private string project;
        private string objectNameTemplate;
        private string fileNameTemplate;
        private int order;
        private List<MappingProperty> properties;
        private bool enabled;
        #endregion

        #region Properties
        [XmlAttribute(AttributeName = "Type")]
        public string Type
        {
            get { return type; }
            set { type = value; }
        }

        [XmlAttribute(AttributeName = "Type")]
        public string Template
        {
            get { return template; }
            set { template = value; }
        }

        [XmlAttribute(AttributeName = "ObjectNameTemplate")]
        public string ObjectNameTemplate
        {
            get { return objectNameTemplate; }
            set
            {
                if (objectNameTemplate != value)
                {
                    objectNameTemplate = value;
                    RaisePropertyChanged("ObjectNameTemplate");
                }
            }
        }

        [XmlAttribute(AttributeName = "FileNameTemplate")]
        public string FileNameTemplate
        {
            get { return fileNameTemplate; }
            set
            {
                if (fileNameTemplate != value)
                {
                    fileNameTemplate = value;
                    RaisePropertyChanged("FileNameTemplate");
                }
            }
        }

        [XmlAttribute(AttributeName = "Order")]
        public int Order
        {
            get { return order; }
            set
            {
                if (order != value)
                {
                    order = value;
                    RaisePropertyChanged("Order");
                }
            }
        }

        [XmlAttribute(AttributeName = "Project")]
        public string Project
        {
            get { return project; }
            set
            {
                if (project != value)
                {
                    project = value;
                    RaisePropertyChanged("Project");
                }
            }
        }

        [XmlAttribute(AttributeName="Properties")]
        public List<MappingProperty> Properties
        {
            get { return properties; }
        }

        [XmlAttribute(AttributeName="Enabled")]
        public bool Enabled
        {
            get { return enabled; }
            set
            {
                if (enabled != value)
                {
                    enabled = value;
                    RaisePropertyChanged("Enabled");
                }
            }
        }
        #endregion

        #region Constructors
        public TemplateMapping(
            string type = "",
            string template = "",
            string project = "",
            string objectNameTemplate = "",
            string fileNameTemplate = "",
            int order = 0,
            bool enabled = true)
        {
            this.type = type;
            this.template = template;
            this.project = project;
            this.objectNameTemplate = objectNameTemplate;
            this.fileNameTemplate = fileNameTemplate;
            this.order = order;
            this.enabled = enabled;
            this.properties = new List<MappingProperty>();
        }

        public TemplateMapping()
            : this("", "", "", "", "", 0, true)
        {
        }
        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion

        #region IEquatable<TemplateMapping> Members

        public bool Equals(TemplateMapping other)
        {
            if (other == null)
            {
                return false;
            }
            else
            {
                if (!String.Equals(this.FileNameTemplate, other.FileNameTemplate))
                    return false;
                if (!String.Equals(this.ObjectNameTemplate, other.ObjectNameTemplate))
                    return false;
                if (this.Order != other.Order)
                    return false;
                if (!String.Equals(this.Project, other.Project))
                    return false;
                if (!String.Equals(this.Template, other.Template))
                    return false;
                if (!String.Equals(this.Type, other.Type))
                    return false;
                if (!Object.Equals(this.Properties, other.Properties))
                    return false;
                if (this.Enabled != other.Enabled)
                    return false;
                
                return true;
            }
        }

        public override bool Equals(object other)
        {
            if (other == null)
            {
                return false;
            }

            if (this.GetType() != other.GetType())
            {
                return false;
            }

            // safe because of the GetType check
            TemplateMapping mapping = (TemplateMapping)other;

            return this.Equals(mapping);
        }
        #endregion

        public static bool operator ==(TemplateMapping left, TemplateMapping right)
        {
            if (Object.Equals(left, null) && Object.Equals(right, null))
            {
                return true;
            }
            if (Object.Equals(left, null) && !Object.Equals(right, null))
            {
                return false;
            }
            if (!Object.Equals(left, null) && Object.Equals(right, null))
            {
                return false;
            }
            else
            {
                return left.Equals(right);
            }
        }

        public static bool operator !=(TemplateMapping left, TemplateMapping right)
        {
            return !(left == right);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #region ICloneable Members

        public object Clone()
        {
            TemplateMapping clone = new TemplateMapping(Type, Template, Project, ObjectNameTemplate, FileNameTemplate, Order, Enabled);
            
            clone.Properties.AddRange(
                Properties
                .Select(p => new MappingProperty() { Key = p.Key, Value = p.Value })
            );

            return clone;
        }

        #endregion
    }
}
